﻿// cobang.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>



// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门提示: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
#include<iostream>
#include<string>
#include<fstream>
#include<iomanip>
int a[90], b[90];
int k = 0;
using namespace std;
class CGobang
{

private:

	char chSort;
	int nWin;
	int nLose;
	static int nDraw;
public:
	static char achBoard[19][19];

	static int nSize;

	CGobang(char  chsort)
	{

		chSort = chsort;
		nWin = nLose = nDraw = 0;
	}

	friend void huiqi();

	static void savefile();

	static void readBoard();

	void continute();

	void PlayTurn(void);

	int Judge();

	void Win(void);

	void Lose(void);

	static void Draw(void);

	void PrintInfo(void);

	static void PrintBoard(void);

	static int GetFull(void);

	static void InitialBoard(void);
};
char CGobang::achBoard[19][19];

int CGobang::nSize = 0;

int CGobang::nDraw = 0;


void CGobang::Draw()
{

	cout << "\n\n\t\t平局!\n\n";
	nDraw++;
}

void CGobang::InitialBoard()
{
	for (int i = 0; i <nSize;i++)
		for (int j = 0; j < nSize; j++)
			achBoard[i][j] = ' ';
}


void CGobang::PrintBoard()
{
	int i, j;
	cout << endl;
	cout << setw(5) << endl;
	for (i = 1; i <= nSize; i++)
	{

		cout << setw(4) << i;
	}
	cout << endl;
	for (i = 0; i < nSize; i++)
	{

		cout << setw(3) << endl;
		cout << i + 1;
		for (j = 0; j < nSize; j++)
			cout << achBoard[i][j] << "|";
		cout << endl;
	}
}


int CGobang::GetFull()
{

	for (int i = 0; i < nSize; i++)
		for (int j = 0; j < nSize; j++)
			if (achBoard[i][j] == ' ')
				return 0;
	return 1;
}


void CGobang::Win()
{
	cout << "\n\n\t\t" << chSort << "方获胜!\n\n";
	nWin++;
}

void CGobang::savefile()
{
	ofstream outfile("C++.txt", ios::out);
	if (!outfile)
	{
		cerr << "open file error" << endl;
		exit(1);
	}
	for (int i = 0; i < nSize; i++)
		for (int j = 0; j < nSize; j++)
			outfile.write((char*)&achBoard[i][j], sizeof(achBoard[i][j]));
	outfile.close();
}


void CGobang::Lose()
{

	nLose++;
}


void CGobang::PlayTurn(void)
{

	int nRow, nCol;
	char choice1, choice2;
	do {

		cout << "\t现在该" << chSort << "方下棋,请输入棋盘坐标(x,y):";
		cin >> nRow >> nCol;
		if (nRow > nSize || nCol > nSize)
		{
			cout << "\t输入的坐标越界,x与y的范围应小于等于" << "nSize" << "请重新输入\n";
		}
		else if (nRow > 0 && nCol > 0 && achBoard[nRow - 1][nCol - 1] != ' ')
			cout << "\t棋盘(" << nRow << "," << nCol << ")处已有棋子,请重新输入\n";
		
			else if (nRow == 0 && nCol == 0)
			{

				cout << "\t确认你想要结束游戏吗(y,n)?";
				cin.get();
				cin >> choice1;
				if (choice1 == 'y' || choice1 == 'Y')
				{

					cout << "\t是否保存(y,n)?:";
					cin.get();
					cin >> choice2;
					if (choice2 == 'y' || choice2 == 'Y')
					{
						CGobang::savefile();
						cout << "\t保存成功,欢迎下次再玩!\n";
						exit(1);
					}
					else
					{

						cout << "\t游戏结束,欢迎再次使用五子棋游戏!";
						cout << endl;
						exit(0);
					}
				}
			}
			else {

				achBoard[nRow - 1][nCol - 1] = chSort;
				a[k] = nRow - 1;
				b[k] = nCol - 1;
				k++;
				break;
			}
	} while (1);
}


int CGobang::Judge()
{
	int i, j;
	for (i = 0; i < nSize; i++)
		for (j = 0; j < nSize; j++)
		{
			if (achBoard[i][j] == chSort)
			{
				if (j + 4 < nSize)
				{
					if (achBoard[i][j + 1] == chSort && achBoard[i][j + 2] == chSort && achBoard[i][j + 3] == chSort && achBoard[i][j + 4] == chSort)
						return 1;
				}
				if (i + 4 < nSize)
				{
					if (achBoard[i + 1][j] == chSort && achBoard[i + 2][j] == chSort && achBoard[i + 3][j] == chSort && achBoard[i + 4][j] == chSort)
						return 1;
				}
				if (i + 4 < nSize&&j + 4 < nSize)
				{

					if (achBoard[i + 1][j + 1] == chSort && achBoard[i + 2][j + 2] == chSort && achBoard[i + 3][j + 3] == chSort && achBoard[i + 4][j + 4] == chSort)
						return 1;
				}
				if (i - 4 > 0 && j + 4 < nSize)
				{
					if (achBoard[i - 1][j + 1] == chSort && achBoard[i - 2][j + 2] == chSort && achBoard[i - 3][j + 3] == chSort && achBoard[i - 4][j + 4] == chSort)
						return 1;
				}
			}
		}
	return 0;
}


void CGobang::PrintInfo(void)
{
	cout << "Size" << "方共计赢" << nWin << "局,输" << nLose << "局,平" << nDraw << "局。" << endl;
}

void CGobang::readBoard()
{
	ifstream infile("C++.txt", ios::in);
	if (!infile)
	{
		cerr << "open file error!" << endl;
		exit(1);
	}
	else
	{
		for (int i = 0; i < nSize; i++)
			for (int j = 0; j < nSize; j++)
				infile.read((char*)&achBoard[i][j], sizeof(achBoard[i][j]));
		infile.close();
	}
}


void huiqi()
{
	k--;
	CGobang::achBoard[a[k]][b[k]] = ' ';
	k--;
	CGobang::achBoard[a[k]][b[k]] = ' ';
	CGobang::PrintBoard();
}


void PrintRule(void)
{

	cout << "\t☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆\n\n";
	cout << "\tW欢迎使用五子棋游戏!" << endl << endl;
	cout << "\t☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆\n\n";
	cout << "\t游戏规则:" << endl;
	cout << "\t1.每一步输入要下棋子的格子的x,y坐标,按Enter键\n";
	cout << "\t2.每一方首先五个棋子连成一线即判获胜\n";
	cout << "\t3.当棋子布满棋盘但仍无获胜方即为平局\n";
	cout << "\t4.一局结束后,若想继续按Y键,若退出则按其他键\n";
	cout << "\t5.若想中途退出游戏，请输入(0,0),再按提示保存游戏\n";
	cout << "\t6.悔棋请输入(-1,0)\n";
	cout << "\t6.X方先行\n";
	cout << "\n\n\t\t请按任意键开始下棋!\n\n";
}


int JudgePlay(CGobang &SideX, CGobang &SideO)
{
	if (SideX.Judge())
	{
		SideX.Win();
		SideO.Lose();
		return 1;
	}
	else if (SideO.Judge())
	{
		SideO.Win();
		return 1;
	}
	else
		return 0;
}


void Play(CGobang&SideX, CGobang&SideO)
{
	while (1)
	{
		system("cls");
		cout << "\t*************************************\n";
		cout << "\t悔棋请输入(-1,0)Wn";
		cout << "\t中途退出请输出(0,0)\n";
		cout << "\t*************************************\n";
		CGobang::PrintBoard();//出棋
		SideO.PlayTurn();
		if (JudgePlay(SideX, SideO))
			break;
		if (CGobang::GetFull())
		{

			CGobang::Draw();
			break;
		}		
			if (CGobang::GetFull())
			{
				CGobang::Draw();
					break;
			}
	}
}


void continute()
{
	char str;
	cin.get();
	cout << "\t你是否接着玩上一次的游戏(y/n)";
	cin >> str;
	if (str == 'Y' || str == 'y')
		CGobang::readBoard();
	else
		cout << "\t请玩新游戏\n";
}




int main(void)
{
	CGobang SideX('@'), SideO('O');
	system("cls");
	PrintRule();
	cin.get();
	string strChoice;
	do
	{

		cout << "请选择棋盘(10~19)";
		cin >> CGobang::nSize;
		cout << endl;
		if (CGobang::nSize > 19 || CGobang::nSize < 10)
		{
			cout << "请重新输入";
			cin >> CGobang::nSize;
			cout << endl;
		}
		else
		{

			system("PAUSE");
			system("cls");
			CGobang::InitialBoard();
			continute();
			Play(SideX, SideO);
			cout << "是否(Y/N)";
			cin >> strChoice;
		}
	} while (strChoice == "Y" || strChoice == "y");
	SideX.PrintInfo();
	SideO.PrintInfo();
	cout << "\n\n欢迎再次使用五子棋游戏!" << endl << endl;
	return 0;
}